Core.Storage.Configuration = function(observable) {
	this.values = {};
	this.visible = {};
	this.observable = observable;
};

Core.Storage.Configuration.prototype = {
	
	/**
	 * Returns the property value with the highest priority available.
	 * @param String property
	 */
	get: function(property) {
		var values = this._getValues(property),
			visible = this._getVisibility(property);

		return values[visible] ? values[visible].value : undefined;
	},
	
	/**
	 * Returns all existing properties names.
	 */
	keys: function() {
		return Object.keys(this.values);
	},
	
	/**
	 * Sets the configuration property with the value and priority on behalf of the given object.
	 * Will throw an exception if the priority slot is already marked with other object
	 * which will hold its override (method will try to resolve override conflict first).
	 * 
	 * @param String property
	 * @param Any value
	 * @param Object object - object modifying the property.
	 * @param Integer priority
	 */
	override: function(property, value, object, priority) {
		var values = this._getValues(property),
			visible = this._getVisibility(property);
		
		this._assertNoOverrideConflict(property, object, priority);
		values[priority] = {uid: object, value: value};
		
		if(priority <= visible) {
			this.visible[property] = priority;
			if(this.observable) { this.observable.propertyChanged(property); }
		}
	},
	
	/**
	 * Tries to resolve property override conflict.
	 * Throws an exception if the current override owner differs from the new one and will not clear its override.
	 */
	_assertNoOverrideConflict: function(property, object, priority) {
		var values = this._getValues(property);
		
		if(values[priority] && values[priority].uid !== object) {
			var resolveFn = values[priority].uid.resolveOverrideConflict;
			
			if(!resolveFn || !resolveFn(property, priority, this)) {
				throw new Error("OverrideConflict '" + property + "' with priority  '" + priority + "' in storage '" + Env.stamp(this) + "'.");
			}
		}
	},
	
	/**
	 * Clears the configuration property corresponding to the given priority.
	 * Will silently ignore if the priority slot is marked with other object
	 * (would mean that the value was set on successful resolve of the override conflict).
	 * 
	 * @param String property
	 * @param Object object - object modifying the property.
	 * @param Integer priority
	 */
	clearOverride: function(property, object, priority) {
		var values = this._getValues(property),
			visible = this._getVisibility(property);
		
		if(!values[priority] || values[priority].uid !== object) { return; }
		else { values[priority] = undefined; }
		
		if(priority === visible) {
			this.visible[property] = this._calcVisibility(property);
			if(this.observable) { this.observable.propertyChanged(property); }
		}
	},
	
	/**
	 * Returns the given property values visibility.
	 * @param String property
	 */
	_getVisibility: function(property) {
		if(this.visible[property] === undefined) { this.visible[property] = 20; }
		return this.visible[property];
	},
	
	/**
	 * Calculates the given property values visibility.
	 * @param String property
	 */
	_calcVisibility: function(property, values) {
		var i = -1, values = this._getValues(property);
		while(++i < 20) {
			if(values[i]) { console.log(i);return i; }
		}
		return 20;
	},
	
	/**
	 * Returns the property priority array.
	 * @param String property
	 */
	_getValues: function(property) {
		if(this.values[property] === undefined) { this.values[property] = []; }
		return this.values[property];
	}
};